﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;

namespace Goldlight.SampleApplication
{
    public class CloseTab : Decorator //TabItem
    {
        private Geometry chromeGeometry;
        private Double slopeScalar = 0.20d;

        public static readonly DependencyProperty BackgroundProperty = Border.BackgroundProperty.AddOwner(typeof(CloseTab));
        public static readonly DependencyProperty BorderBrushProperty = Border.BorderBrushProperty.AddOwner(typeof(CloseTab));

        public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(
            "BorderThickness",
            typeof(Double),
            typeof(CloseTab),
            new FrameworkPropertyMetadata(
                0.0d,
                FrameworkPropertyMetadataOptions.AffectsMeasure |
                FrameworkPropertyMetadataOptions.AffectsArrange));

        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
            "CornerRadius",
            typeof(Double),
            typeof(CloseTab),
            new FrameworkPropertyMetadata(
                0.0d,
                FrameworkPropertyMetadataOptions.AffectsMeasure |
                FrameworkPropertyMetadataOptions.AffectsArrange));

        public Brush Background
        {
            get { return (Brush)GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }

        public Brush BorderBrush
        {
            get { return (Brush)GetValue(BorderBrushProperty); }
            set { SetValue(BorderBrushProperty, value); }
        }

        public Double BorderThickness
        {
            get { return (Double)GetValue(BorderThicknessProperty); }
            set { SetValue(BorderThicknessProperty, value); }
        }

        public Double CornerRadius
        {
            get { return (Double)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }

        protected override Size MeasureOverride(Size constraint)
        {
            var size = new Size();
            var length = 2 * this.BorderThickness;
            var nonContentSize = new Size(length, length);

            if (base.Child != null)
            {
                base.Child.Measure(constraint);
                Size desiredSize = base.Child.DesiredSize;
                size.Width = desiredSize.Width / (1 - slopeScalar) + nonContentSize.Width;
                size.Height = desiredSize.Height + nonContentSize.Height;
                return size;
            }

            return nonContentSize;
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            var length = 2 * this.BorderThickness;
            var nonContentSize = new Size(length, length);
            var arrangedRect = new Rect(
                arrangeSize.Width * slopeScalar - nonContentSize.Width,
                0,
                arrangeSize.Width - arrangeSize.Width * slopeScalar + nonContentSize.Width,
                arrangeSize.Height);

            arrangedRect.Inflate(-nonContentSize.Width, -nonContentSize.Height);

            if (base.Child != null)
            {
                base.Child.Arrange(arrangedRect);
            }

            var geometryBoundingBox = new Rect(new Size(arrangeSize.Width - 2 * this.BorderThickness, arrangeSize.Height - 2 * this.BorderThickness));
            chromeGeometry = GenerateGeometry(geometryBoundingBox, this.CornerRadius);

            return arrangeSize;
        }

        private Geometry GenerateGeometry(Rect geometryBoundingBox, Double radius)
        {
            var streamGeometry = new StreamGeometry();
            var isFilled = this.Background != null;
            var isStroked = this.BorderThickness > 0 && this.BorderBrush != null;
            var arcSize = new Size(radius, radius);

            //var startPoint = new Point(geometryBoundingBox.Width * slopeScalar, 0);
            var startPoint = new Point(8.9, 0);
            var endPoint = new Point(0, geometryBoundingBox.Height);
            var slopeVector = (startPoint - endPoint) / 2;
            var matrix = Matrix.Identity;
            matrix.Rotate(-10 / Math.PI);
            var point1 = slopeVector * matrix + endPoint;

            matrix = Matrix.Identity;
            matrix.Rotate(10 / Math.PI);
            var point2 = -slopeVector * matrix + startPoint;

            using (var context = streamGeometry.Open())
            {
                context.BeginFigure(startPoint, isFilled, false);
                context.LineTo(new Point(geometryBoundingBox.Width - radius, 0), isStroked, true);
                context.ArcTo(new Point(geometryBoundingBox.Width, radius), arcSize, 90, false, SweepDirection.Clockwise, isStroked, true);
                context.LineTo(new Point(geometryBoundingBox.Width, geometryBoundingBox.Height), isStroked, true);
                context.LineTo(endPoint, false, true);
                context.BezierTo(point1, point2, startPoint, isStroked, true);
            }

            if (streamGeometry.CanFreeze)
            {
                streamGeometry.Freeze();
            }
            return streamGeometry;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            if (chromeGeometry != null && !chromeGeometry.Bounds.IsEmpty)
            {
                drawingContext.DrawGeometry(this.Background, new Pen(this.BorderBrush, this.BorderThickness), chromeGeometry);
            }
        }
    }
}
